package crp.core.resource.domain.repositories;

import com.qwlabs.lang.S2;
import crp.core.resource.domain.models.TimetableResourceSyncRecordEntity;
import crp.core.shared.ProcessStatus;
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;

import javax.enterprise.context.ApplicationScoped;
import javax.persistence.LockModeType;
import java.time.Instant;
import java.util.Optional;

@ApplicationScoped
public class TimetableResourceSyncRecordRepository implements PanacheRepositoryBase<TimetableResourceSyncRecordEntity, String> {

    public int upsert(Instant before, Integer priority) {
        String sql = "insert into timetable_resource_sync_record (timetable_id, process_status, priority)" +
                " select id, :processStatus, :priority from timetable" +
                " where id not in (select timetable_id from timetable_resource_sync_record)" +
                " and end_at <:before" +
                " and space_id is not null and space_id!=''" +
                " on conflict(timetable_id) do update set process_status=:processStatus";
        return getEntityManager().createNativeQuery(sql)
                .setParameter("priority", priority)
                .setParameter("processStatus", ProcessStatus.IDLE.toString())
                .setParameter("before", before)
                .executeUpdate();
    }

    public int resetByCourseId(String courseId, Integer priority) {
        if (S2.isBlank(courseId)) {
            return 0;
        }
        String hql = "update TimetableResourceSyncRecordEntity" +
                " set processStatus=:processStatus, priority=:priority" +
                " where timetable.id in (select id from TimetableEntity where course.id=:courseId)";
        return getEntityManager()
                .createQuery(hql)
                .setParameter("priority", priority)
                .setParameter("courseId", courseId)
                .setParameter("processStatus", ProcessStatus.IDLE)
                .executeUpdate();
    }

    public int resetByStatus(ProcessStatus processStatus, Integer priority) {
        String hql = "update TimetableResourceSyncRecordEntity" +
                " set processStatus=:toProcessStatus, priority=:priority" +
                " where processStatus=:fromProcessStatus";
        return getEntityManager()
                .createQuery(hql)
                .setParameter("toProcessStatus", ProcessStatus.IDLE)
                .setParameter("fromProcessStatus", processStatus)
                .setParameter("priority", priority)
                .executeUpdate();
    }

    public int resetByTimeout(Instant before, Integer priority) {
        String hql = "update TimetableResourceSyncRecordEntity" +
                " set processStatus=:toProcessStatus, priority=:priority" +
                " where processStatus=:fromProcessStatus and processStartAt<:before";
        return getEntityManager()
                .createQuery(hql)
                .setParameter("toProcessStatus", ProcessStatus.IDLE)
                .setParameter("fromProcessStatus", ProcessStatus.PROCESSING)
                .setParameter("before", before)
                .setParameter("priority", priority)
                .executeUpdate();
    }

    public Optional<String> peekAnyIdByDay() {
        String sql = "select id" +
                " from timetable_resource_sync_record" +
                " where process_status=:processStatus" +
                " order by priority desc, date_part('dow', updated_at) asc, random() asc";
        return getEntityManager()
                .createNativeQuery(sql)
                .setParameter("processStatus", ProcessStatus.IDLE.toString())
                .setMaxResults(1)
                .getResultStream()
                .findFirst();
    }

    public TimetableResourceSyncRecordEntity lock(String id) {
        return findById(id, LockModeType.PESSIMISTIC_WRITE);
    }
}
